https://www.kaggle.com/c/web-traffic-time-series-forecasting/data
Each of these time series represent a number of daily views of a different Wikipedia article. The page/article names contain the Wikipedia project (e.g. en.wikipedia.org), type of access/traffic (e.g. desktop) and type of agent (e.g. spid). In other words, each article name has the following format: ‘name_project_access_agent’ (e.g. ‘AKB48_zh.wikipedia.org_all-access_spid’). Unfortunately, the data source for this dataset does not distinguish between traffic values of zero and missing values. A missing value may mean the traffic was zero or that the data is not available for that day.
train_2 <- read.csv('train_2.csv') #The second stage will use training data up until September 1st, 2017.
library(dplyr)
library(tibble)
library(tidyr)
library(stringr)
train <- train_2 #[complete.cases(train_2), ]
tdates <- train %>% select(-Page) #df with no page names
#separating the mediawiki, wikimedia, and wikipedia data
foo <- train %>% select(Page) %>% rownames_to_column()
mediawiki <- foo %>% filter(str_detect(Page, "mediawiki"))
wikimedia <- foo %>% filter(str_detect(Page, "wikimedia"))
wikipedia <- foo %>% filter(str_detect(Page, "wikipedia")) %>%
filter(!str_detect(Page, "wikimedia")) %>%
filter(!str_detect(Page, "mediawiki"))
#separating the page name into topic, location, access, and agent
wikipedia <- wikipedia %>%
separate(Page, into = c("foo", "bar"), sep = ".wikipedia.org_") %>%
separate(foo, into = c("article", "locale"), sep = -3) %>%
separate(bar, into = c("access", "agent"), sep = "_") %>%
mutate(locale = str_sub(locale,2,3))
wikimedia <- wikimedia %>%
separate(Page, into = c("article", "bar"), sep = "_commons.wikimedia.org_") %>%
separate(bar, into = c("access", "agent"), sep = "_") %>%
add_column(locale = "wikmed")
mediawiki <- mediawiki %>%
separate(Page, into = c("article", "bar"), sep = "_www.mediawiki.org_") %>%
separate(bar, into = c("access", "agent"), sep = "_") %>%
add_column(locale = "medwik")
#rejoining mediawiki, wikimedia, and wikipedia into one df
tpages <- wikipedia %>%
full_join(wikimedia, by = c("rowname", "article", "locale", "access", "agent")) %>%
full_join(mediawiki, by = c("rowname", "article", "locale", "access", "agent"))
sample_n(tpages, 5)
t(tdates[6279,773:800])
bg.fr.desk <- ts(t(tdates[6279,]),frequency = 7)
bg.fr.mobl <- ts(t(tdates[53362,]), frequency = 7)
bg.fr.spid <- ts(t(tdates[129691,]), frequency = 7)
bg.fr.all <- bg.fr.desk + bg.fr.mobl + bg.fr.spid
bg.en.desk <- ts(t(tdates[11057,]), frequency = 7)
bg.en.mobl <- ts(t(tdates[73051,]), frequency = 7)
bg.en.spid <- ts(t(tdates[34899,]), frequency = 7)
bg.en.all <- bg.en.desk + bg.en.mobl + bg.en.spid
bg.de.desk <- ts(t(tdates[67313,]), frequency = 7)
bg.de.mobl <- ts(t(tdates[116365,]), frequency = 7)
bg.de.spid <- ts(t(tdates[48744,]), frequency = 7)
bg.de.all <- bg.de.desk + bg.de.mobl + bg.de.spid
bg.es.desk <- ts(t(tdates[70902,]), frequency = 7)
bg.es.mobl <- ts(t(tdates[95498,]), frequency = 7)
bg.es.spid <- ts(t(tdates[143106,]), frequency = 7)
bg.es.all <- bg.es.desk + bg.es.mobl + bg.es.spid
bg.all <- bg.en.all + bg.de.all + bg.fr.all + bg.es.all
plot(bg.en.all, ylim = c(0,45000), main = "Bill Gates - English Wikipedia")
legend("topright", legend = c("All","Desktop", "Mobile", "Spider"), col = c(1,2,3,4), lty=1, cex=0.8,box.lty=0)
lines(bg.en.desk, col = 2)
lines(bg.en.mobl, col = 3)
lines(bg.en.spid, col = 4)

plot(bg.de.all, ylim = c(0,8000), main = "Bill Gates - German Wikipedia")
lines(bg.de.desk, col = 2)
lines(bg.de.mobl, col = 3)
lines(bg.de.spid, col = 4)

plot(bg.fr.all, ylim = c(0,27000), main = "Bill Gates - French Wikipedia")
lines(bg.fr.desk, col = 2)
lines(bg.fr.mobl, col = 3)
lines(bg.fr.spid, col = 4)

plot(bg.es.all, ylim = c(0,18000), main = "Bill Gates - Spanish Wikipedia")
lines(bg.es.desk, col = 2)
lines(bg.es.mobl, col = 3)
lines(bg.es.spid, col = 4)

plot(bg.all, ylim = c(0,72000), main = "Bill Gates - All Wikipedia")
legend("topright", legend = c("All","English", "German", "French", "Spanish"), col = c(1,2,3,4,5), lty=1, cex=0.8,
box.lty=0)
lines(bg.en.all, col = 2)
lines(bg.de.all, col = 3)
lines(bg.fr.all, col = 4)
lines(bg.es.all, col = 5)

train <- window(bg.all, end = c(111,3))
test <- window(bg.all, start = c(111,4))
bg.auto.arima <- auto.arima(train, seasonal = F, stepwise = F)
bg.auto.arima #ARIMA(4,1,1) #AIC=15,029.9
Series: train
ARIMA(4,1,1)
Coefficients:
ar1 ar2 ar3 ar4 ma1
0.2824 -0.0852 -0.1457 -0.1763 -0.7081
s.e. 0.0856 0.0441 0.0421 0.0531 0.0857
sigma^2 estimated as 16933916: log likelihood=-7518.3
AIC=15048.59 AICc=15048.7 BIC=15076.48
bg.auto.arima.forecast <- forecast(bg.auto.arima, h=30)
plot(bg.auto.arima.forecast)

plot(bg.auto.arima.forecast$residuals, main = 'Residuals of Nonseasonal Arima Model')

acf(bg.auto.arima.forecast$residuals, 50)

accuracy(bg.auto.arima.forecast, test)
ME RMSE MAE MPE MAPE MASE ACF1 Theil's U
Training set -22.45622 4099.082 2476.969 -1.931765 9.959495 0.7392464 -0.003013109 NA
Test set 1734.44132 3250.966 2530.823 6.809611 11.496360 0.7553189 0.381103704 1.038294
train <- window(bg.all, end = c(111,3))
test <- window(bg.all, start = c(111,4))
bg.auto.sarima <- auto.arima(train, stepwise = F)
bg.auto.sarima #ARIMA(1,1,1)(2,0,0)[7] #AIC=15,003.24
Series: train
ARIMA(1,1,1)(2,0,0)[7]
Coefficients:
ar1 ma1 sar1 sar2
0.5089 -0.9712 0.1769 0.134
s.e. 0.0354 0.0125 0.0367 0.036
sigma^2 estimated as 16381873: log likelihood=-7506.44
AIC=15022.88 AICc=15022.96 BIC=15046.13
bg.auto.sarima.forecast <- forecast(bg.auto.sarima, h=30)
plot(bg.auto.sarima.forecast)

plot(bg.auto.sarima.forecast$residuals, main = 'Residuals of Seasonal Arima Model')

acf(bg.auto.sarima.forecast$residuals, 50)

accuracy(bg.auto.sarima.forecast, test)
ME RMSE MAE MPE MAPE MASE ACF1 Theil's U
Training set -31.12515 4034.341 2401.153 -2.148731 9.653707 0.7166192 -0.02309289 NA
Test set 605.44325 2791.224 2092.539 1.297238 9.855258 0.6245138 0.40633026 0.8993862
#the forecast is less volatile/tame
plot(test, main = 'Forecasted (blue) versus Actual (black)'); lines(bg.auto.sarima.forecast$mean,col=4)

library(forecast)
library("hts")
#nodes <- list(4, c(3, 3, 3, 3))
#group into language, then into total
abc <- cbind(bg.en.desk, bg.en.mobl, bg.en.spid,
bg.de.desk, bg.de.mobl, bg.de.spid,
bg.fr.desk, bg.fr.mobl, bg.fr.spid,
bg.es.desk, bg.es.mobl, bg.es.spid)
train <- hts(window(abc, end = c(111,3)), characters = c(6,4))
test <- hts(window(abc, start = c(111,4)), characters = c(6,4))
smatrix(train)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 1 1 1 1 1 1 1 1 1 1 1 1
[2,] 1 1 1 0 0 0 0 0 0 0 0 0
[3,] 0 0 0 1 1 1 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 1 1 1 0 0 0
[5,] 0 0 0 0 0 0 0 0 0 1 1 1
[6,] 1 0 0 0 0 0 0 0 0 0 0 0
[7,] 0 1 0 0 0 0 0 0 0 0 0 0
[8,] 0 0 1 0 0 0 0 0 0 0 0 0
[9,] 0 0 0 1 0 0 0 0 0 0 0 0
[10,] 0 0 0 0 1 0 0 0 0 0 0 0
[11,] 0 0 0 0 0 1 0 0 0 0 0 0
[12,] 0 0 0 0 0 0 1 0 0 0 0 0
[13,] 0 0 0 0 0 0 0 1 0 0 0 0
[14,] 0 0 0 0 0 0 0 0 1 0 0 0
[15,] 0 0 0 0 0 0 0 0 0 1 0 0
[16,] 0 0 0 0 0 0 0 0 0 0 1 0
[17,] 0 0 0 0 0 0 0 0 0 0 0 1
plot(train) #aggregates some of them in the middle, then all at the to

bg.hts.fcst <- forecast(train, method="bu", fmethod = "arima", h=30, keep.resid = T, weights = 'ols')
#Forecasts are distributed in the hierarchy using bottom-up, top-down, middle-out, and optimal combination methods.
#"comb", "bu", "mo", "tdgsa", "tdgsf", "tdfp"
plot(bg.hts.fcst)

plot(rowSums(bg.hts.fcst$residuals), main = 'Residuals of Hierarchical Arima Model', type = 'l')

acf(rowSums(bg.hts.fcst$residuals),50)

accuracy.gts(bg.hts.fcst, test, level = 0)
Total
ME 311.8174560
RMSE 2686.0089123
MAE 2041.3629309
MAPE 9.7727548
MPE -0.1215421
MASE 0.6092405
library(TSA)
train <- window(bg.all, end = c(111,3))
test <- window(bg.all, start = c(111,4))
which(bg.auto.sarima.forecast$residuals >= 11000)
[1] 39 120 153 155 182 218 238 239 243 362 364 486 566 614 629 758 759
pulse1 <- 1*(seq(train) == 39)
pulse2 <- 1*(seq(train) == 120)
pulse3 <- 1*(seq(train) == 155)
pulse4 <- 1*(seq(train) == 182)
pulse5 <- 1*(seq(train) == 218)
pulse6 <- 1*(seq(train) == 238)
pulse7 <- 1*(seq(train) == 362)
pulse8 <- 1*(seq(train) == 364)
pulse9 <- 1*(seq(train) == 486)
pulse10 <- 1*(seq(train) == 566)
pulse11 <- 1*(seq(train) == 614)
pulse12 <- 1*(seq(train) == 629)
pulse13 <- 1*(seq(train) == 758)
xtransf.dataframe = data.frame(pulse1, pulse2, pulse3, pulse4, pulse5, pulse6, pulse7,
pulse8, pulse9, pulse10, pulse11, pulse12, pulse13)
transfer.list = list(c(1,0), c(1,0), c(1,0), c(1,0), c(1,0), c(1,0), c(1,0),
c(1,0), c(1,0), c(1,0), c(1,0), c(1,0), c(1,0))
bg.pulse <- arimax(log(train),
order=c(1,1,1),
seasonal=list(order=c(2,0,0), period=7),
transfer=transfer.list,
xtransf=xtransf.dataframe,
method='ML')
#bg.pulse
tf1<-stats::filter(1*(seq(1:(length(train)+30))==39),filter=bg.pulse$coef[5], method='recursive',side=1) * (bg.pulse$coef[6])
tf2<-stats::filter(1*(seq(1:(length(train)+30))==120),filter=bg.pulse$coef[7], method='recursive',side=1) * (bg.pulse$coef[8])
tf3<-stats::filter(1*(seq(1:(length(train)+30))==155),filter=bg.pulse$coef[9], method='recursive',side=1) * (bg.pulse$coef[10])
tf4<-stats::filter(1*(seq(1:(length(train)+30))==182),filter=bg.pulse$coef[11], method='recursive',side=1) * (bg.pulse$coef[12])
tf5<-stats::filter(1*(seq(1:(length(train)+30))==218),filter=bg.pulse$coef[13], method='recursive',side=1) * (bg.pulse$coef[14])
tf6<-stats::filter(1*(seq(1:(length(train)+30))==238),filter=bg.pulse$coef[15], method='recursive',side=1) * (bg.pulse$coef[16])
tf7<-stats::filter(1*(seq(1:(length(train)+30))==362),filter=bg.pulse$coef[17], method='recursive',side=1) * (bg.pulse$coef[18])
tf8<-stats::filter(1*(seq(1:(length(train)+30))==364),filter=bg.pulse$coef[19], method='recursive',side=1) * (bg.pulse$coef[20])
tf9<-stats::filter(1*(seq(1:(length(train)+30))==486),filter=bg.pulse$coef[21], method='recursive',side=1) * (bg.pulse$coef[22])
tf10<-stats::filter(1*(seq(1:(length(train)+30))==566),filter=bg.pulse$coef[23], method='recursive',side=1) * (bg.pulse$coef[24])
tf11<-stats::filter(1*(seq(1:(length(train)+30))==614),filter=bg.pulse$coef[25], method='recursive',side=1) * (bg.pulse$coef[26])
tf12<-stats::filter(1*(seq(1:(length(train)+30))==629),filter=bg.pulse$coef[27], method='recursive',side=1) * (bg.pulse$coef[28])
tf13<-stats::filter(1*(seq(1:(length(train)+30))==758),filter=bg.pulse$coef[29], method='recursive',side=1) * (bg.pulse$coef[30])
tf <- tf1 + tf2 + tf3 + tf4 + tf5 + tf6 + tf7 + tf8 + tf9 + tf10 + tf11 + tf12 + tf13
plot(exp(tf), col = 4, main = "Effect of Pulses")

forecast.arima<-Arima(log(train), order=c(1,1,1),
seasonal = list(order=c(2,0,0), period=7),
xreg=tf[1:(length(tf)-30)])
bg.arimax.predict <- predict(forecast.arima, n.ahead = 30, newxreg=tf[774:length(tf)])
bg.arimax.predict$pred <- exp(bg.arimax.predict$pred)
plot(c(train,bg.arimax.predict$pred), col =2, type = 'l'); lines(ts(bg.all), col = 1)

plot(bg.arimax.predict$pred-test, main = 'Residuals of Seasonal Arima Model')

#MAE
mean(abs(bg.arimax.predict$pred-test))
[1] 2876.462
#MPE
sum((test-bg.arimax.predict$pred)/test)*100/(length(test)-1)
[1] 11.93955
#RMSE
sqrt(mean((bg.arimax.predict$pred-test)^2))
[1] 3727.543
pulsesx <- c(39, 120, 155, 182, 218, 239, 362, 364, 486, 566, 614, 630, 759)
ts.plot(ts(c(train),frequency = 7), main = "Bill Gates Time Series with Pulses Highlighted"); points(pulsesx/7+.9,train[pulsesx],col = 'blue')
#like the seasonal arima, it doesn't have as extreme swings in the data
lines(bg.arimax.predict$pred,col=2)

LS0tCnRpdGxlOiAiVGltZSBTZXJpZXMgR3JvdXAgUHJvamVjdCIKYXV0aG9yOiAiQW5uIEVpdHJoZWltLCBBbHZpbiBIYXJ5YW50bywgRGFuIFRhbGxhcmljbyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUKLS0tCgpodHRwczovL3d3dy5rYWdnbGUuY29tL2Mvd2ViLXRyYWZmaWMtdGltZS1zZXJpZXMtZm9yZWNhc3RpbmcvZGF0YQoKRWFjaCBvZiB0aGVzZSB0aW1lIHNlcmllcyByZXByZXNlbnQgYSBudW1iZXIgb2YgZGFpbHkgdmlld3Mgb2YgYSBkaWZmZXJlbnQgV2lraXBlZGlhIGFydGljbGUuIFRoZSBwYWdlL2FydGljbGUgbmFtZXMgY29udGFpbiB0aGUgV2lraXBlZGlhIHByb2plY3QgKGUuZy4gZW4ud2lraXBlZGlhLm9yZyksIHR5cGUgb2YgYWNjZXNzL3RyYWZmaWMgKGUuZy4gZGVza3RvcCkgYW5kIHR5cGUgb2YgYWdlbnQgKGUuZy4gc3BpZCkuIEluIG90aGVyIHdvcmRzLCBlYWNoIGFydGljbGUgbmFtZSBoYXMgdGhlIGZvbGxvd2luZyBmb3JtYXQ6ICduYW1lX3Byb2plY3RfYWNjZXNzX2FnZW50JyAoZS5nLiAnQUtCNDhfemgud2lraXBlZGlhLm9yZ19hbGwtYWNjZXNzX3NwaWQnKS4gVW5mb3J0dW5hdGVseSwgdGhlIGRhdGEgc291cmNlIGZvciB0aGlzIGRhdGFzZXQgZG9lcyBub3QgZGlzdGluZ3Vpc2ggYmV0d2VlbiB0cmFmZmljIHZhbHVlcyBvZiB6ZXJvIGFuZCBtaXNzaW5nIHZhbHVlcy4gQSBtaXNzaW5nIHZhbHVlIG1heSBtZWFuIHRoZSB0cmFmZmljIHdhcyB6ZXJvIG9yIHRoYXQgdGhlIGRhdGEgaXMgbm90IGF2YWlsYWJsZSBmb3IgdGhhdCBkYXkuCmBgYHtyfQp0cmFpbl8yIDwtIHJlYWQuY3N2KCd0cmFpbl8yLmNzdicpICNUaGUgc2Vjb25kIHN0YWdlIHdpbGwgdXNlIHRyYWluaW5nIGRhdGEgdXAgdW50aWwgU2VwdGVtYmVyIDFzdCwgMjAxNy4KYGBgCgoKYGBge3IsIGVjaG8gPSBGQUxTRX0KI3RyYWluXzEgPC0gcmVhZC5jc3YoJ3RyYWluXzEuY3N2JykgI1ZpZXdzIHN0YXJ0aW5nIGZyb20gSnVseSwgMXN0LCAyMDE1IHVwIHVudGlsIERlY2VtYmVyIDMxc3QsIDIwMTYuCiNrZXlfMSA8LSByZWFkLmNzdigna2V5XzEuY3N2JykgI2dpdmVzIHRoZSBtYXBwaW5nIGJldHdlZW4gdGhlIHBhZ2UgbmFtZXMgYW5kIHRoZSBzaG9ydGVuZWQgSWQgY29sdW1uIHVzZWQgZm9yIHByZWRpY3Rpb24KI2tleV8yIDwtIHJlYWQuY3N2KCdrZXlfMi5jc3YnKQojc2FtcGxlX3N1Ym1pc3Npb25fMSA8LSByZWFkLmNzdignc2FtcGxlX3N1Ym1pc3Npb25fMS5jc3YnKSAjVGhlIGxlYWRlcmJvYXJkIGR1cmluZyB0aGUgdHJhaW5pbmcgc3RhZ2UgaXMgYmFzZWQgb24gdHJhZmZpYyBmcm9tIEphbnVhcnksIDFzdCwgMjAxNyB1cCB1bnRpbCBNYXJjaCAxc3QsIDIwMTcuCiNzYW1wbGVfc3VibWlzc2lvbl8yIDwtIHJlYWQuY3N2KCdzYW1wbGVfc3VibWlzc2lvbl8yLmNzdicpICNUaGUgZmluYWwgcmFua2luZyBvZiB0aGUgY29tcGV0aXRpb24gd2lsbCBiZSBiYXNlZCBvbiBwcmVkaWN0aW9ucyBvZiBkYWlseSB2aWV3cyBiZXR3ZWVuIFNlcHRlbWJlciAxM3RoLCAyMDE3IGFuZCBOb3ZlbWJlciAxM3RoLCAyMDE3IGZvciBlYWNoIGFydGljbGUgaW4gdGhlIGRhdGFzZXQuIApgYGAKCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKCnRyYWluIDwtIHRyYWluXzIgI1tjb21wbGV0ZS5jYXNlcyh0cmFpbl8yKSwgXQp0ZGF0ZXMgPC0gdHJhaW4gJT4lIHNlbGVjdCgtUGFnZSkgI2RmIHdpdGggbm8gcGFnZSBuYW1lcwoKI3NlcGFyYXRpbmcgdGhlIG1lZGlhd2lraSwgd2lraW1lZGlhLCBhbmQgd2lraXBlZGlhIGRhdGEKZm9vIDwtIHRyYWluICU+JSBzZWxlY3QoUGFnZSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpCm1lZGlhd2lraSA8LSBmb28gJT4lIGZpbHRlcihzdHJfZGV0ZWN0KFBhZ2UsICJtZWRpYXdpa2kiKSkKd2lraW1lZGlhIDwtIGZvbyAlPiUgZmlsdGVyKHN0cl9kZXRlY3QoUGFnZSwgIndpa2ltZWRpYSIpKQp3aWtpcGVkaWEgPC0gZm9vICU+JSBmaWx0ZXIoc3RyX2RldGVjdChQYWdlLCAid2lraXBlZGlhIikpICU+JSAKICBmaWx0ZXIoIXN0cl9kZXRlY3QoUGFnZSwgIndpa2ltZWRpYSIpKSAlPiUgCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KFBhZ2UsICJtZWRpYXdpa2kiKSkKCiNzZXBhcmF0aW5nIHRoZSBwYWdlIG5hbWUgaW50byB0b3BpYywgbG9jYXRpb24sIGFjY2VzcywgYW5kIGFnZW50Cndpa2lwZWRpYSA8LSB3aWtpcGVkaWEgJT4lCiAgc2VwYXJhdGUoUGFnZSwgaW50byA9IGMoImZvbyIsICJiYXIiKSwgc2VwID0gIi53aWtpcGVkaWEub3JnXyIpICU+JQogIHNlcGFyYXRlKGZvbywgaW50byA9IGMoImFydGljbGUiLCAibG9jYWxlIiksIHNlcCA9IC0zKSAlPiUKICBzZXBhcmF0ZShiYXIsIGludG8gPSBjKCJhY2Nlc3MiLCAiYWdlbnQiKSwgc2VwID0gIl8iKSAlPiUKICBtdXRhdGUobG9jYWxlID0gc3RyX3N1Yihsb2NhbGUsMiwzKSkKd2lraW1lZGlhIDwtIHdpa2ltZWRpYSAlPiUKICBzZXBhcmF0ZShQYWdlLCBpbnRvID0gYygiYXJ0aWNsZSIsICJiYXIiKSwgc2VwID0gIl9jb21tb25zLndpa2ltZWRpYS5vcmdfIikgJT4lCiAgc2VwYXJhdGUoYmFyLCBpbnRvID0gYygiYWNjZXNzIiwgImFnZW50IiksIHNlcCA9ICJfIikgJT4lCiAgYWRkX2NvbHVtbihsb2NhbGUgPSAid2lrbWVkIikKbWVkaWF3aWtpIDwtIG1lZGlhd2lraSAlPiUKICBzZXBhcmF0ZShQYWdlLCBpbnRvID0gYygiYXJ0aWNsZSIsICJiYXIiKSwgc2VwID0gIl93d3cubWVkaWF3aWtpLm9yZ18iKSAlPiUKICBzZXBhcmF0ZShiYXIsIGludG8gPSBjKCJhY2Nlc3MiLCAiYWdlbnQiKSwgc2VwID0gIl8iKSAlPiUKICBhZGRfY29sdW1uKGxvY2FsZSA9ICJtZWR3aWsiKQoKI3Jlam9pbmluZyBtZWRpYXdpa2ksIHdpa2ltZWRpYSwgYW5kIHdpa2lwZWRpYSBpbnRvIG9uZSBkZgp0cGFnZXMgPC0gd2lraXBlZGlhICU+JQogIGZ1bGxfam9pbih3aWtpbWVkaWEsIGJ5ID0gYygicm93bmFtZSIsICJhcnRpY2xlIiwgImxvY2FsZSIsICJhY2Nlc3MiLCAiYWdlbnQiKSkgJT4lCiAgZnVsbF9qb2luKG1lZGlhd2lraSwgYnkgPSBjKCJyb3duYW1lIiwgImFydGljbGUiLCAibG9jYWxlIiwgImFjY2VzcyIsICJhZ2VudCIpKQoKc2FtcGxlX24odHBhZ2VzLCA1KQpgYGAKCgpgYGB7ciwgZWNobyA9IEZBTFNFfQojc2VhcmNoaW5nIGZvciBwYWdlcwojdHBhZ2VzICU+JSBmaWx0ZXIoYXJ0aWNsZSA9PSAiQmlsbF9HYXRlcyIpCiAgI1RoZV9MYXN0X0d1YXJkaWFuCiAgI0JhcmFja19PYmFtYQogICNCaWxsX0dhdGVzCiAgI0JpdGNvaW4KICAjQ29jYS1Db2xhCiAgI0ludGVybmV0CiAgI01lZ2hhbl9NYXJrbGUKICAjTWVyeWxfU3RyZWVwCiAgI01pY2hlbGxlX09iYW1hCiAgI1RoZV9CZWF0bGVzCiAgI1RyaWF0aGxvbgogICNXaGF0c0FwcAogICNXaWxsaWFtX1NoYWtlc3BlYXJlCgojdHBhZ2VzICU+JSAgZ3JvdXBfYnkoYXJ0aWNsZSkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSBmaWx0ZXIoY291bnQgPiA5KQpgYGAKdCh0ZGF0ZXNbNjI3OSw3NzM6ODAwXSkKYGBge3J9CmJnLmZyLmRlc2sgPC0gdHModCh0ZGF0ZXNbNjI3OSxdKSxmcmVxdWVuY3kgPSA3KQpiZy5mci5tb2JsIDwtIHRzKHQodGRhdGVzWzUzMzYyLF0pLCBmcmVxdWVuY3kgPSA3KQpiZy5mci5zcGlkIDwtIHRzKHQodGRhdGVzWzEyOTY5MSxdKSwgZnJlcXVlbmN5ID0gNykKYmcuZnIuYWxsIDwtIGJnLmZyLmRlc2sgKyBiZy5mci5tb2JsICsgYmcuZnIuc3BpZAoKYmcuZW4uZGVzayA8LSB0cyh0KHRkYXRlc1sxMTA1NyxdKSwgZnJlcXVlbmN5ID0gNykKYmcuZW4ubW9ibCA8LSB0cyh0KHRkYXRlc1s3MzA1MSxdKSwgZnJlcXVlbmN5ID0gNykKYmcuZW4uc3BpZCA8LSB0cyh0KHRkYXRlc1szNDg5OSxdKSwgZnJlcXVlbmN5ID0gNykKYmcuZW4uYWxsIDwtIGJnLmVuLmRlc2sgKyBiZy5lbi5tb2JsICsgYmcuZW4uc3BpZAoKYmcuZGUuZGVzayA8LSB0cyh0KHRkYXRlc1s2NzMxMyxdKSwgZnJlcXVlbmN5ID0gNykKYmcuZGUubW9ibCA8LSB0cyh0KHRkYXRlc1sxMTYzNjUsXSksIGZyZXF1ZW5jeSA9IDcpCmJnLmRlLnNwaWQgPC0gdHModCh0ZGF0ZXNbNDg3NDQsXSksIGZyZXF1ZW5jeSA9IDcpCmJnLmRlLmFsbCA8LSBiZy5kZS5kZXNrICsgYmcuZGUubW9ibCArIGJnLmRlLnNwaWQKCmJnLmVzLmRlc2sgPC0gdHModCh0ZGF0ZXNbNzA5MDIsXSksIGZyZXF1ZW5jeSA9IDcpCmJnLmVzLm1vYmwgPC0gdHModCh0ZGF0ZXNbOTU0OTgsXSksIGZyZXF1ZW5jeSA9IDcpCmJnLmVzLnNwaWQgPC0gdHModCh0ZGF0ZXNbMTQzMTA2LF0pLCBmcmVxdWVuY3kgPSA3KQpiZy5lcy5hbGwgPC0gYmcuZXMuZGVzayArIGJnLmVzLm1vYmwgKyBiZy5lcy5zcGlkCgpiZy5hbGwgPC0gYmcuZW4uYWxsICsgYmcuZGUuYWxsICsgYmcuZnIuYWxsICsgYmcuZXMuYWxsCmBgYAoKYGBge3J9CnBsb3QoYmcuZW4uYWxsLCB5bGltID0gYygwLDQ1MDAwKSwgbWFpbiA9ICJCaWxsIEdhdGVzIC0gRW5nbGlzaCBXaWtpcGVkaWEiKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiQWxsIiwiRGVza3RvcCIsICJNb2JpbGUiLCAiU3BpZGVyIiksIGNvbCA9IGMoMSwyLDMsNCksIGx0eT0xLCBjZXg9MC44LGJveC5sdHk9MCkKbGluZXMoYmcuZW4uZGVzaywgY29sID0gMikKbGluZXMoYmcuZW4ubW9ibCwgY29sID0gMykKbGluZXMoYmcuZW4uc3BpZCwgY29sID0gNCkKCnBsb3QoYmcuZGUuYWxsLCB5bGltID0gYygwLDgwMDApLCBtYWluID0gIkJpbGwgR2F0ZXMgLSBHZXJtYW4gV2lraXBlZGlhIikKbGluZXMoYmcuZGUuZGVzaywgY29sID0gMikKbGluZXMoYmcuZGUubW9ibCwgY29sID0gMykKbGluZXMoYmcuZGUuc3BpZCwgY29sID0gNCkKCnBsb3QoYmcuZnIuYWxsLCB5bGltID0gYygwLDI3MDAwKSwgbWFpbiA9ICJCaWxsIEdhdGVzIC0gRnJlbmNoIFdpa2lwZWRpYSIpCmxpbmVzKGJnLmZyLmRlc2ssIGNvbCA9IDIpCmxpbmVzKGJnLmZyLm1vYmwsIGNvbCA9IDMpCmxpbmVzKGJnLmZyLnNwaWQsIGNvbCA9IDQpCgpwbG90KGJnLmVzLmFsbCwgeWxpbSA9IGMoMCwxODAwMCksIG1haW4gPSAiQmlsbCBHYXRlcyAtIFNwYW5pc2ggV2lraXBlZGlhIikKbGluZXMoYmcuZXMuZGVzaywgY29sID0gMikKbGluZXMoYmcuZXMubW9ibCwgY29sID0gMykKbGluZXMoYmcuZXMuc3BpZCwgY29sID0gNCkKCgpwbG90KGJnLmFsbCwgeWxpbSA9IGMoMCw3MjAwMCksIG1haW4gPSAiQmlsbCBHYXRlcyAtIEFsbCBXaWtpcGVkaWEiKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiQWxsIiwiRW5nbGlzaCIsICJHZXJtYW4iLCAiRnJlbmNoIiwgIlNwYW5pc2giKSwgY29sID0gYygxLDIsMyw0LDUpLCBsdHk9MSwgY2V4PTAuOCwKICAgICAgIGJveC5sdHk9MCkKbGluZXMoYmcuZW4uYWxsLCBjb2wgPSAyKQpsaW5lcyhiZy5kZS5hbGwsIGNvbCA9IDMpCmxpbmVzKGJnLmZyLmFsbCwgY29sID0gNCkKbGluZXMoYmcuZXMuYWxsLCBjb2wgPSA1KQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CiN0byBoZWxwIHdpdGggcGxvdHRpbmcKcGxvdF9yb3duciA8LSBmdW5jdGlvbihyb3ducil7CiAgYXJ0IDwtIHRwYWdlcyAlPiUgZmlsdGVyKHJvd25hbWUgPT0gcm93bnIpICU+JSAuJGFydGljbGUKICBsb2MgPC0gdHBhZ2VzICU+JSBmaWx0ZXIocm93bmFtZSA9PSByb3ducikgJT4lIC4kbG9jYWxlCiAgYWNjIDwtIHRwYWdlcyAlPiUgZmlsdGVyKHJvd25hbWUgPT0gcm93bnIpICU+JSAuJGFjY2VzcwogIGV4dHJhY3RfdHMocm93bnIpICU+JQogICAgZ2dwbG90KGFlcyhkYXRlcywgdmlld3MpKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2xvciA9ICJibHVlIiwgc3BhbiA9IDEvNSkgKwogICAgbGFicyh0aXRsZSA9IHN0cl9jKGFydCwgIiAtICIsIGxvYywgIiAtICIsIGFjYykpCn0KCnBsb3Rfcm93bnJfbG9nIDwtIGZ1bmN0aW9uKHJvd25yKXsKICBhcnQgPC0gdHBhZ2VzICU+JSBmaWx0ZXIocm93bmFtZSA9PSByb3ducikgJT4lIC4kYXJ0aWNsZQogIGxvYyA8LSB0cGFnZXMgJT4lIGZpbHRlcihyb3duYW1lID09IHJvd25yKSAlPiUgLiRsb2NhbGUKICBhY2MgPC0gdHBhZ2VzICU+JSBmaWx0ZXIocm93bmFtZSA9PSByb3ducikgJT4lIC4kYWNjZXNzCiAgZXh0cmFjdF90c19ucm0ocm93bnIpICU+JQogICAgZ2dwbG90KGFlcyhkYXRlcywgdmlld3MpKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2xvciA9ICJibHVlIiwgc3BhbiA9IDEvNSkgKwogICAgbGFicyh0aXRsZSA9IHN0cl9jKGFydCwgIiAtICIsIGxvYywgIiAtICIsIGFjYykpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArIGxhYnMoeSA9ICJsb2cgdmlld3MiKQp9CgpwbG90X3Jvd25yX3pvb20gPC0gZnVuY3Rpb24ocm93bnIsIHN0YXJ0LCBlbmQpewogIGFydCA8LSB0cGFnZXMgJT4lIGZpbHRlcihyb3duYW1lID09IHJvd25yKSAlPiUgLiRhcnRpY2xlCiAgbG9jIDwtIHRwYWdlcyAlPiUgZmlsdGVyKHJvd25hbWUgPT0gcm93bnIpICU+JSAuJGxvY2FsZQogIGFjYyA8LSB0cGFnZXMgJT4lIGZpbHRlcihyb3duYW1lID09IHJvd25yKSAlPiUgLiRhY2Nlc3MKICBleHRyYWN0X3RzKHJvd25yKSAlPiUKICAgIGZpbHRlcihkYXRlcyA+IHltZChzdGFydCkgJiBkYXRlcyA8PSB5bWQoZW5kKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKGRhdGVzLCB2aWV3cykpICsKICAgIGdlb21fbGluZSgpICsKICAgICNnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBjb2xvciA9ICJibHVlIiwgc3BhbiA9IDEvNSkgKwogICAgI2Nvb3JkX2NhcnRlc2lhbih4bGltID0geW1kKGMoc3RhcnQsZW5kKSkpICsgIAogICAgbGFicyh0aXRsZSA9IHN0cl9jKGFydCwgIiAtICIsIGxvYywgIiAtICIsIGFjYykpCn0KYGBgCgpgYGB7ciBub25zZWFzb25hbCBhcmltYX0KdHJhaW4gPC0gd2luZG93KGJnLmFsbCwgZW5kID0gYygxMTEsMykpCnRlc3QgPC0gd2luZG93KGJnLmFsbCwgc3RhcnQgPSBjKDExMSw0KSkKCmJnLmF1dG8uYXJpbWEgPC0gYXV0by5hcmltYSh0cmFpbiwgc2Vhc29uYWwgPSBGLCBzdGVwd2lzZSA9IEYpCmJnLmF1dG8uYXJpbWEgI0FSSU1BKDQsMSwxKSAgI0FJQz0xNSwwMjkuOQpiZy5hdXRvLmFyaW1hLmZvcmVjYXN0IDwtIGZvcmVjYXN0KGJnLmF1dG8uYXJpbWEsIGg9MzApCnBsb3QoYmcuYXV0by5hcmltYS5mb3JlY2FzdCkKcGxvdChiZy5hdXRvLmFyaW1hLmZvcmVjYXN0JHJlc2lkdWFscywgbWFpbiA9ICdSZXNpZHVhbHMgb2YgTm9uc2Vhc29uYWwgQXJpbWEgTW9kZWwnKQphY2YoYmcuYXV0by5hcmltYS5mb3JlY2FzdCRyZXNpZHVhbHMsIDUwKQphY2N1cmFjeShiZy5hdXRvLmFyaW1hLmZvcmVjYXN0LCB0ZXN0KQpgYGAKCgpgYGB7ciBzZWFzb25hbCBhcmltYX0KdHJhaW4gPC0gd2luZG93KGJnLmFsbCwgZW5kID0gYygxMTEsMykpCnRlc3QgPC0gd2luZG93KGJnLmFsbCwgc3RhcnQgPSBjKDExMSw0KSkKCmJnLmF1dG8uc2FyaW1hIDwtIGF1dG8uYXJpbWEodHJhaW4sIHN0ZXB3aXNlID0gRikKYmcuYXV0by5zYXJpbWEgI0FSSU1BKDEsMSwxKSgyLDAsMClbN10gICNBSUM9MTUsMDAzLjI0CmJnLmF1dG8uc2FyaW1hLmZvcmVjYXN0IDwtIGZvcmVjYXN0KGJnLmF1dG8uc2FyaW1hLCBoPTMwKQpwbG90KGJnLmF1dG8uc2FyaW1hLmZvcmVjYXN0KQpwbG90KGJnLmF1dG8uc2FyaW1hLmZvcmVjYXN0JHJlc2lkdWFscywgbWFpbiA9ICdSZXNpZHVhbHMgb2YgU2Vhc29uYWwgQXJpbWEgTW9kZWwnKQphY2YoYmcuYXV0by5zYXJpbWEuZm9yZWNhc3QkcmVzaWR1YWxzLCA1MCkKYWNjdXJhY3koYmcuYXV0by5zYXJpbWEuZm9yZWNhc3QsIHRlc3QpCgojdGhlIGZvcmVjYXN0IGlzIGxlc3Mgdm9sYXRpbGUvdGFtZQpwbG90KHRlc3QsIG1haW4gPSAnRm9yZWNhc3RlZCAoYmx1ZSkgdmVyc3VzIEFjdHVhbCAoYmxhY2spJyk7IGxpbmVzKGJnLmF1dG8uc2FyaW1hLmZvcmVjYXN0JG1lYW4sY29sPTQpCmBgYAoKYGBge3IgaGllcmFyY2hpY2FsfQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KCJodHMiKSAKI25vZGVzIDwtIGxpc3QoNCwgYygzLCAzLCAzLCAzKSkKI2dyb3VwIGludG8gbGFuZ3VhZ2UsIHRoZW4gaW50byB0b3RhbAphYmMgPC0gY2JpbmQoYmcuZW4uZGVzaywgYmcuZW4ubW9ibCwgYmcuZW4uc3BpZCwKICAgICAgICAgICAgIGJnLmRlLmRlc2ssIGJnLmRlLm1vYmwsIGJnLmRlLnNwaWQsCiAgICAgICAgICAgICBiZy5mci5kZXNrLCBiZy5mci5tb2JsLCBiZy5mci5zcGlkLAogICAgICAgICAgICAgYmcuZXMuZGVzaywgYmcuZXMubW9ibCwgYmcuZXMuc3BpZCkKCnRyYWluIDwtIGh0cyh3aW5kb3coYWJjLCBlbmQgPSBjKDExMSwzKSksIGNoYXJhY3RlcnMgPSBjKDYsNCkpCnRlc3QgPC0gaHRzKHdpbmRvdyhhYmMsIHN0YXJ0ID0gYygxMTEsNCkpLCBjaGFyYWN0ZXJzID0gYyg2LDQpKQoKc21hdHJpeCh0cmFpbikKcGxvdCh0cmFpbikgI2FnZ3JlZ2F0ZXMgc29tZSBvZiB0aGVtIGluIHRoZSBtaWRkbGUsIHRoZW4gYWxsIGF0IHRoZSB0bwpiZy5odHMuZmNzdCA8LSBmb3JlY2FzdCh0cmFpbiwgbWV0aG9kPSJidSIsIGZtZXRob2QgPSAiYXJpbWEiLCBoPTMwLCBrZWVwLnJlc2lkID0gVCwgd2VpZ2h0cyA9ICdvbHMnKQogICAgI0ZvcmVjYXN0cyBhcmUgZGlzdHJpYnV0ZWQgaW4gdGhlIGhpZXJhcmNoeSB1c2luZyBib3R0b20tdXAsIHRvcC1kb3duLCBtaWRkbGUtb3V0LCBhbmQgb3B0aW1hbCBjb21iaW5hdGlvbiBtZXRob2RzLgogICAgIyJjb21iIiwgImJ1IiwgIm1vIiwgInRkZ3NhIiwgInRkZ3NmIiwgInRkZnAiCnBsb3QoYmcuaHRzLmZjc3QpCnBsb3Qocm93U3VtcyhiZy5odHMuZmNzdCRyZXNpZHVhbHMpLCBtYWluID0gJ1Jlc2lkdWFscyBvZiBIaWVyYXJjaGljYWwgQXJpbWEgTW9kZWwnLCB0eXBlID0gJ2wnKQphY2Yocm93U3VtcyhiZy5odHMuZmNzdCRyZXNpZHVhbHMpLDUwKQphY2N1cmFjeS5ndHMoYmcuaHRzLmZjc3QsIHRlc3QsIGxldmVsID0gMCkKYGBgCgpgYGB7ciBhcmltYXh9CmxpYnJhcnkoVFNBKQp0cmFpbiA8LSB3aW5kb3coYmcuYWxsLCBlbmQgPSBjKDExMSwzKSkKdGVzdCA8LSB3aW5kb3coYmcuYWxsLCBzdGFydCA9IGMoMTExLDQpKQoKd2hpY2goYmcuYXV0by5zYXJpbWEuZm9yZWNhc3QkcmVzaWR1YWxzID49IDExMDAwKQoKcHVsc2UxIDwtIDEqKHNlcSh0cmFpbikgPT0gMzkpCnB1bHNlMiA8LSAxKihzZXEodHJhaW4pID09IDEyMCkKcHVsc2UzIDwtIDEqKHNlcSh0cmFpbikgPT0gMTU1KQpwdWxzZTQgPC0gMSooc2VxKHRyYWluKSA9PSAxODIpCnB1bHNlNSA8LSAxKihzZXEodHJhaW4pID09IDIxOCkKcHVsc2U2IDwtIDEqKHNlcSh0cmFpbikgPT0gMjM4KQpwdWxzZTcgPC0gMSooc2VxKHRyYWluKSA9PSAzNjIpCnB1bHNlOCA8LSAxKihzZXEodHJhaW4pID09IDM2NCkKcHVsc2U5IDwtIDEqKHNlcSh0cmFpbikgPT0gNDg2KQpwdWxzZTEwIDwtIDEqKHNlcSh0cmFpbikgPT0gNTY2KQpwdWxzZTExIDwtIDEqKHNlcSh0cmFpbikgPT0gNjE0KQpwdWxzZTEyIDwtIDEqKHNlcSh0cmFpbikgPT0gNjI5KQpwdWxzZTEzIDwtIDEqKHNlcSh0cmFpbikgPT0gNzU4KQoKeHRyYW5zZi5kYXRhZnJhbWUgPSBkYXRhLmZyYW1lKHB1bHNlMSwgcHVsc2UyLCBwdWxzZTMsIHB1bHNlNCwgcHVsc2U1LCBwdWxzZTYsIHB1bHNlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1bHNlOCwgcHVsc2U5LCBwdWxzZTEwLCBwdWxzZTExLCBwdWxzZTEyLCBwdWxzZTEzKQp0cmFuc2Zlci5saXN0ID0gbGlzdChjKDEsMCksIGMoMSwwKSwgYygxLDApLCBjKDEsMCksIGMoMSwwKSwgYygxLDApLCBjKDEsMCksCiAgICAgICAgICAgICAgICAgICAgIGMoMSwwKSwgYygxLDApLCBjKDEsMCksIGMoMSwwKSwgYygxLDApLCBjKDEsMCkpCgpiZy5wdWxzZSA8LSBhcmltYXgobG9nKHRyYWluKSwKICAgICAgICAgICAgICAgICAgIG9yZGVyPWMoMSwxLDEpLAogICAgICAgICAgICAgICAgICAgc2Vhc29uYWw9bGlzdChvcmRlcj1jKDIsMCwwKSwgcGVyaW9kPTcpLAogICAgICAgICAgICAgICAgICAgdHJhbnNmZXI9dHJhbnNmZXIubGlzdCwKICAgICAgICAgICAgICAgICAgIHh0cmFuc2Y9eHRyYW5zZi5kYXRhZnJhbWUsCiAgICAgICAgICAgICAgICAgICBtZXRob2Q9J01MJykKI2JnLnB1bHNlCnRmMTwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT0zOSksZmlsdGVyPWJnLnB1bHNlJGNvZWZbNV0sIG1ldGhvZD0ncmVjdXJzaXZlJyxzaWRlPTEpICogKGJnLnB1bHNlJGNvZWZbNl0pCnRmMjwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT0xMjApLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzddLCBtZXRob2Q9J3JlY3Vyc2l2ZScsc2lkZT0xKSAqIChiZy5wdWxzZSRjb2VmWzhdKQp0ZjM8LXN0YXRzOjpmaWx0ZXIoMSooc2VxKDE6KGxlbmd0aCh0cmFpbikrMzApKT09MTU1KSxmaWx0ZXI9YmcucHVsc2UkY29lZls5XSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsxMF0pCnRmNDwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT0xODIpLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzExXSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsxMl0pCnRmNTwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT0yMTgpLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzEzXSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsxNF0pCnRmNjwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT0yMzgpLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzE1XSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsxNl0pCnRmNzwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT0zNjIpLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzE3XSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsxOF0pCnRmODwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT0zNjQpLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzE5XSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsyMF0pCnRmOTwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT00ODYpLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzIxXSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsyMl0pCnRmMTA8LXN0YXRzOjpmaWx0ZXIoMSooc2VxKDE6KGxlbmd0aCh0cmFpbikrMzApKT09NTY2KSxmaWx0ZXI9YmcucHVsc2UkY29lZlsyM10sIG1ldGhvZD0ncmVjdXJzaXZlJyxzaWRlPTEpICogKGJnLnB1bHNlJGNvZWZbMjRdKQp0ZjExPC1zdGF0czo6ZmlsdGVyKDEqKHNlcSgxOihsZW5ndGgodHJhaW4pKzMwKSk9PTYxNCksZmlsdGVyPWJnLnB1bHNlJGNvZWZbMjVdLCBtZXRob2Q9J3JlY3Vyc2l2ZScsc2lkZT0xKSAqIChiZy5wdWxzZSRjb2VmWzI2XSkKdGYxMjwtc3RhdHM6OmZpbHRlcigxKihzZXEoMToobGVuZ3RoKHRyYWluKSszMCkpPT02MjkpLGZpbHRlcj1iZy5wdWxzZSRjb2VmWzI3XSwgbWV0aG9kPSdyZWN1cnNpdmUnLHNpZGU9MSkgKiAoYmcucHVsc2UkY29lZlsyOF0pCnRmMTM8LXN0YXRzOjpmaWx0ZXIoMSooc2VxKDE6KGxlbmd0aCh0cmFpbikrMzApKT09NzU4KSxmaWx0ZXI9YmcucHVsc2UkY29lZlsyOV0sIG1ldGhvZD0ncmVjdXJzaXZlJyxzaWRlPTEpICogKGJnLnB1bHNlJGNvZWZbMzBdKQoKdGYgPC0gdGYxICsgdGYyICsgdGYzICsgdGY0ICsgdGY1ICsgdGY2ICsgdGY3ICsgdGY4ICsgdGY5ICsgdGYxMCArIHRmMTEgKyB0ZjEyICsgdGYxMwpwbG90KGV4cCh0ZiksIGNvbCA9IDQsIG1haW4gPSAiRWZmZWN0IG9mIFB1bHNlcyIpCgpmb3JlY2FzdC5hcmltYTwtQXJpbWEobG9nKHRyYWluKSwgb3JkZXI9YygxLDEsMSksCiAgICAgICAgICAgICAgICAgICAgICBzZWFzb25hbCA9IGxpc3Qob3JkZXI9YygyLDAsMCksIHBlcmlvZD03KSwKICAgICAgICAgICAgICAgICAgICAgIHhyZWc9dGZbMToobGVuZ3RoKHRmKS0zMCldKQoKYmcuYXJpbWF4LnByZWRpY3QgPC0gcHJlZGljdChmb3JlY2FzdC5hcmltYSwgbi5haGVhZCA9IDMwLCBuZXd4cmVnPXRmWzc3NDpsZW5ndGgodGYpXSkKYmcuYXJpbWF4LnByZWRpY3QkcHJlZCA8LSBleHAoYmcuYXJpbWF4LnByZWRpY3QkcHJlZCkKCnBsb3QoYyh0cmFpbixiZy5hcmltYXgucHJlZGljdCRwcmVkKSwgY29sID0yLCB0eXBlID0gJ2wnKTsgbGluZXModHMoYmcuYWxsKSwgY29sID0gMSkKCnBsb3QoYmcuYXJpbWF4LnByZWRpY3QkcHJlZC10ZXN0LCBtYWluID0gJ1Jlc2lkdWFscyBvZiBTZWFzb25hbCBBcmltYSBNb2RlbCcpCiNNQUUgCm1lYW4oYWJzKGJnLmFyaW1heC5wcmVkaWN0JHByZWQtdGVzdCkpCiNNUEUgCnN1bSgodGVzdC1iZy5hcmltYXgucHJlZGljdCRwcmVkKS90ZXN0KSoxMDAvKGxlbmd0aCh0ZXN0KS0xKQojUk1TRQpzcXJ0KG1lYW4oKGJnLmFyaW1heC5wcmVkaWN0JHByZWQtdGVzdCleMikpCgpwdWxzZXN4IDwtIGMoMzksIDEyMCwgMTU1LCAxODIsIDIxOCwgMjM5LCAzNjIsIDM2NCwgNDg2LCA1NjYsIDYxNCwgNjMwLCA3NTkpCnRzLnBsb3QodHMoYyh0cmFpbiksZnJlcXVlbmN5ID0gNyksIG1haW4gPSAiQmlsbCBHYXRlcyBUaW1lIFNlcmllcyB3aXRoIFB1bHNlcyBIaWdobGlnaHRlZCIpOyBwb2ludHMocHVsc2VzeC83Ky45LHRyYWluW3B1bHNlc3hdLGNvbCA9ICdibHVlJykKCiNsaWtlIHRoZSBzZWFzb25hbCBhcmltYSwgaXQgZG9lc24ndCBoYXZlIGFzIGV4dHJlbWUgc3dpbmdzIGluIHRoZSBkYXRhCmxpbmVzKGJnLmFyaW1heC5wcmVkaWN0JHByZWQsY29sPTIpCmBgYAoKCgoKCgoKCg==